
#pragma once


#include <cstdint>
#include <cstdlib>
#include <limits>

#include <type_traits>

namespace oled_basic {

#if __has_include("oled_app_config.hpp")

    #include "oled_app_config.hpp"

    #ifndef _OLED_BASIC_ENABLE_GRAYSCALE
        #define _OLED_BASIC_ENABLE_GRAYSCALE (0)
    #endif

#else

/////////////////////////// CONFIG START /////////////////////////////

    // 启用灰阶相关的功能。如果设为0，可以减少ROM 占用和代码复杂度，但不能正确处理灰阶屏和灰阶显示数据
    #ifndef _OLED_BASIC_ENABLE_GRAYSCALE
        #define _OLED_BASIC_ENABLE_GRAYSCALE (1)
    #endif

    // 用于设置像素坐标的类型，默认uint8_t，所以屏幕最大坐标是(255, 255)
    // 市面上貌似大部分单色OLED 或LCD 的尺寸都小于这个值，
    // 但是定制的LED 点阵有可能大于这个尺寸
    using PixelIndexType = uint_fast8_t;

    // 灰阶屏一次要发送多个字节，默认最多16 级灰度，每个显示数据需要4 字节。
    // 设置为uint8_t，可以关闭部分灰阶处理功能，去除相应的ROM 和性能占用。
    // 设置为uint16_t 或uint64_t，对应最大灰度等级为4 级或256 级。
    // using DisplayUnitType = uint32_t;

    // 向屏幕打印整数时，无符号整数最大宽度。较小的尺寸可以略微优化ROM 尺寸和RAM 占用
    using UnsignedType = uint32_t;

    // 限制可打印的整数进制最小为10 进制，否则最小为2 进制。
    // 对于uint32_t 类型，若要打印为二进制，最大需要32 字节的缓冲区，
    // 限制最小为10 进制，就只要10 字节缓冲区
    constexpr bool LIMIT_NUM_BASE = true;

    // 输出浮点时精度固定为两位小数，能略微优化速度，最大三位小数
    // 设置为0，则精度在运行时动态设置。值大于0，则浮点输出函数的精度参数无效。
    //constexpr unsigned FIXED_FLOAT_PRECISION = 2;


    // I2C 通信频率，默认400kHz。如果CPU 频率较低，就无法达到400kHz，但仍然能以较低频率运行，不会发生错误
    constexpr uint32_t HIGH_SPEED_I2C_FREQUENCY = 400'000;
    constexpr uint32_t LOW_SPEED_I2C_FREQUENCY = 100'000;

/////////////////////////// CONFIG END /////////////////////////////

#endif

// 有符号整数宽度必须小于等于无符号数
using SignedType = std::make_signed_t<UnsignedType>;

// static_assert(sizeof(UnsignedType) >= sizeof(SignedType));

constexpr UnsignedType UNSIGNED_MAX = static_cast<UnsignedType>(0) - 1;

// 显示二进制数字时的最大宽度，不包括负号
constexpr uint8_t MAX_NUMBER_WIDTH = sizeof(UnsignedType) * 8;


namespace hide {

    /**
     * @brief 根据无符号整数类型T，计算对应的无符号十进制数最大宽度
     * 
     * @tparam T 
     */
    template <typename T>
    struct limited_number_width {};

    template <>
    struct limited_number_width<uint8_t> {
        static constexpr uint8_t value = 3;  // 255
    };

    template <>
    struct limited_number_width<uint16_t> {
        static constexpr uint8_t value = 5; // 65535
    };


    template <>
    struct limited_number_width<uint32_t> {
        static constexpr uint8_t value = 10; // 4'294'967'296
    };

    template <>
    struct limited_number_width<uint64_t> {
        static constexpr uint8_t value = 20; // 18'446'744'073'709'551'616
    };
}


// 显示十进制数字时的最大宽度，不包括负号
constexpr uint8_t LIMITED_NUMBER_WIDTH = hide::limited_number_width<UnsignedType>::value;

constexpr uint8_t NUMBER_LITERAL_WIDTH = (LIMIT_NUM_BASE) ? LIMITED_NUMBER_WIDTH : MAX_NUMBER_WIDTH;

// constexpr bool ENABLE_GRAYSCALE = sizeof(DisplayUnitType) > 1;

constexpr uint8_t MAX_GRAYSCALE_BIT = 8;

constexpr uint8_t MAX_GRAYSCALE_LEVEL = 0xff >> (8 - MAX_GRAYSCALE_BIT);

// 浮点精度，只支持1 到3 位固定小数
//static_assert(FIXED_FLOAT_PRECISION == 0 || FIXED_FLOAT_PRECISION < 4);

}  // namespace oled_basic
